package main

import (
	"fmt"
	"gin/internal/app/common/util"
	"github.com/gin-gonic/gin"
	"github.com/gocolly/colly/v2"
	"io"
	"net/http"
	"net/url"
	"strings"
	"sync"
)

func main() {
	// 测试访问 http://localhost/PLTV/88888888/224/3221227086/index.m3u8
	// 测试访问2 http://localhost/PLTV/88888888/224/3221227086/index.m3u8?icpid=88888888
	// 等价访问 http://39.134.52.153/PLTV/88888888/224/3221227086/index.m3u8
	// ipurl := "http://39.134.61.219"
	ipurl := "http://39.134.52.153" // 39.134.55.160:80
	configUrl, err := util.GetConfigValue("iptv.url")
	if err != nil {
		fmt.Printf("Error: %v\n", err)
	} else {
		if configUrl != nil {
			ipurl = configUrl.(string)
		}
	}
	router := gin.Default()
	router.GET("/*path", func(c *gin.Context) {
		fmt.Println("辽宁ip源代理: ")
		path := c.Param("path") // 这个path带斜杠
		fmt.Println("path", path)
		// gogin获取所有请求参数
		for key, value := range c.Request.URL.Query() {
			fmt.Println("key", key, "value", value)
		}
		// gogin获取get请求参数map
		// 新建一个map 存储get 请求参数的值
		query := make(map[string]string)
		for key, value := range c.Request.URL.Query() {
			query[key] = value[0]
		}

		if strings.HasSuffix(path, "m3u8") {
			aipurl := ipurl
			fmt.Println("m3u8path", path)
			if strings.HasPrefix(path, "/proxy@") {
				// 替换回来
				newTsUrl := strings.Replace(path, "/proxy@", "http://", -1)
				newipurl := getUrlHost(newTsUrl)
				newpath := strings.Replace(newTsUrl, newipurl, "", -1)

				aipurl = newipurl
				path = newpath
			}
			// 构建完整的 URL 包含查询参数
			reqUrl := buildUrl(aipurl+path, query)
			redurl, body := getm3u8(reqUrl)
			fmt.Println("redurl", redurl)
			fmt.Println("response body ", body)
			if len(redurl) > 0 {
				// 把body改为定制的ts http://ip:port --> proxy@ip@port
				proxyredurl := strings.Replace(redurl, "http://", "proxy@", -1)
				tempbody := ""
				tempbodys := strings.Fields(body)
				for _, value := range tempbodys {
					if strings.HasSuffix(value, "ts") {
						tempbody = tempbody + "/" + proxyredurl + "/" + value + "\r\n"
					} else if strings.HasSuffix(value, "m3u8") {
						tempbody = tempbody + "/" + proxyredurl + "/" + value + "\r\n"
					} else {
						tempbody = tempbody + value + "\r\n"
					}
				}
				body = tempbody
			}

			c.Header("Content-Type", "application/vnd.apple.mpegurl")
			c.String(http.StatusOK, body)
		} else if strings.HasSuffix(path, "ts") {
			aipurl := ipurl
			fmt.Println("tspath", path)
			if strings.HasPrefix(path, "/proxy@") {
				// 替换回来
				newTsUrl := strings.Replace(path, "/proxy@", "http://", -1)
				newipurl := getUrlHost(newTsUrl)
				newpath := strings.Replace(newTsUrl, newipurl, "", -1)

				aipurl = newipurl
				path = newpath
			}
			// 构建完整的 URL 包含查询参数
			reqUrl := buildUrl(aipurl+path, query)
			//这里将原来的getTs改成零拷贝
			resp, err := http.Get(reqUrl)
			if err != nil {
				// 处理错误
				c.AbortWithError(http.StatusInternalServerError, err)
				return
			}
			defer resp.Body.Close()

			c.Header("Content-Type", "video/mpeg")
			_, err = io.Copy(c.Writer, resp.Body)
			if err != nil {
				// 处理错误
				c.AbortWithError(http.StatusInternalServerError, err)
				return
			}
		} else {
			c.String(http.StatusNotFound, "not found, m3u8 or ts required")
		}
	})

	port := 80
	configPort, err := util.GetConfigValue("server.port")
	if err != nil {
		fmt.Printf("Error: %v\n", err)
	} else {
		if configUrl != nil {
			port = configPort.(int)
		}
	}
	// 默认端口是80
	router.Run(":" + fmt.Sprint(port))
	fmt.Println("服务启动成功，端口为：", port)
}

func getm3u8(reqUrl string) (redurl string, body string) {
	var wg sync.WaitGroup

	body = ""
	ch := make(chan string)

	redurl = ""
	d := colly.NewCollector(
		colly.UserAgent("Opera/9.80 (Windows NT 6.1; U; zh-cn) Presto/2.9.168 Version/11.50"))

	// 发出请求时附的回调
	d.OnRequest(func(r *colly.Request) {
		fmt.Println("Visiting", r.URL)
	})

	// 处理重定向时保留查询参数
	d.SetRedirectHandler(func(r *http.Request, via []*http.Request) error {
		fmt.Println("Uncoming Redirecting to", r.URL) // 打印准备重定向的链接
		ch <- r.URL.String()                          // 保留查询参数
		return nil                                    // 不禁止跳转
	})

	// extract status code
	d.OnResponse(func(r *colly.Response) {
		fmt.Println("response received", r.StatusCode)
		fmt.Println("response body ", string(r.Body))
		body = string(r.Body)
	})

	wg.Add(1)
	go func(url string) {
		defer wg.Done() // 确保在请求完成时减少计数
		d.Visit(url)
	}(reqUrl)

	// 等待所有的重定向处理完成
	go func() {
		wg.Wait()
		close(ch) // 所有请求处理完毕，关闭通道
	}()

	// 从通道中接收信息，直到通道关闭
	for redirectURL := range ch {
		fmt.Println("After redirector:", redirectURL)
		redurl = redirectURL
	}

	ourl := reqUrl // 直接使用原始 URL
	if len(redurl) > 0 {
		if ourl == redurl {
			redurl = ""
		}
	}

	return redurl, body
}

func getUrlHost(reqUrl string) string {
	parseUrl, err := url.Parse(reqUrl)
	if err != nil {
		fmt.Println("URL解析出错", err)
		return ""
	}
	host := parseUrl.Scheme + "://" + parseUrl.Host
	fmt.Println("提取的主机地址为", host)
	return host
}

// 构建包含查询参数的完整 URL
func buildUrl(baseURL string, query map[string]string) string {
	u, err := url.Parse(baseURL)
	if err != nil {
		fmt.Println("URL解析出错", err)
		return baseURL
	}
	q := u.Query()
	for key, value := range query {
		q.Set(key, value)
	}
	u.RawQuery = q.Encode()
	return u.String()
}
